/*
 * Copyright (c) 2024 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#ifndef ARMV8_SCR_H
#define ARMV8_SCR_H

#include <plat/config.h>
#include <arch/utils.h>
#include <tools/macros.h>
#include <stdlib/stdint.h>
#include <core/dprintf.h>

#ifdef CONFIG_ARCH_AARCH64

enum __AARCH64_SCR_ISR_EL1_BITS {
    SCR_ISR_BIT_A = 8,
    SCR_ISR_BIT_I = 7,
    SCR_ISR_BIT_F = 6,
};

enum __AARCH64_SCR_SCTLR_EL1_BITS {
    SCR_SCTLR_BIT_TE      = 30,
    SCR_SCTLR_BIT_AFE     = 29,
    SCR_SCTLR_BIT_UCI     = 26,
    SCR_SCTLR_BIT_EE      = 25,
    SCR_SCTLR_BIT_EOE     = 24,
    SCR_SCTLR_BIT_WXN     = 19,
    SCR_SCTLR_BIT_nTWE    = 18,
    SCR_SCTLR_BIT_nTWI    = 16,
    SCR_SCTLR_BIT_UCT     = 15,
    SCR_SCTLR_BIT_DZE     = 14,
    SCR_SCTLR_BIT_I       = 12,
    SCR_SCTLR_BIT_UMA     = 9,
    SCR_SCTLR_BIT_SED     = 8,
    SCR_SCTLR_BIT_ITD     = 7,
    SCR_SCTLR_EL1_nAA     = 6,
    SCR_SCTLR_BIT_CP15BEN = 5,
    SCR_SCTLR_BIT_SA0     = 4,
    SCR_SCTLR_BIT_SA      = 3,
    SCR_SCTLR_BIT_C       = 2,
    SCR_SCTLR_BIT_A       = 1,
    SCR_SCTLR_BIT_M       = 0,
};
SCR_BIT64_RW_FUNCTIONS(SDER32_EL3)

SCR_BIT64_RW_FUNCTIONS(CPACR_EL1)

SCR_BIT64_RW_FUNCTIONS(TTBR0_EL1)
SCR_BIT64_RW_FUNCTIONS(TTBR1_EL1)
SCR_BIT64_RW_FUNCTIONS(TTBR0_EL2)
SCR_BIT64_RW_FUNCTIONS(TTBR1_EL2)
enum __AARCH64_SCR_TTBRx_EL1_BITS {
    SCR_TTBRx_BIT_BASEADDR       = 0,
    SCR_TTBRx_BIT_BASEADDR_WIDTH = 48,

    SCR_TTBRx_BIT_ASID       = 48,
    SCR_TTBRx_BIT_ASID_WIDTH = 16,
};

SCR_BIT64_RW_FUNCTIONS(TCR_EL1)
enum __AARCH64_SCR_TCR_EL1_BITS {
    SCR_TCR_EL1_BIT_TBI1 = 38,
    SCR_TCR_EL1_BIT_TBI0 = 37,

    SCR_TCR_EL1_BIT_AS        = 36,
    SCR_TCR_EL1_BIT_IPShigh   = 34,
    SCR_TCR_EL1_BIT_IPSmid    = 33,
    SCR_TCR_EL1_BIT_IPSlow    = 32,
    SCR_TCR_EL1_BIT_TG1high   = 31,
    SCR_TCR_EL1_BIT_TG1low    = 30,
    SCR_TCR_EL1_BIT_SH1high   = 29,
    SCR_TCR_EL1_BIT_SH1low    = 28,
    SCR_TCR_EL1_BIT_ORGN1high = 27,
    SCR_TCR_EL1_BIT_ORGN1low  = 26,

    SCR_TCR_EL1_BIT_IRGN1high = 25,
    SCR_TCR_EL1_BIT_IRGN1low  = 24,

    SCR_TCR_EL1_BIT_EPD1 = 23,

    SCR_TCR_EL1_BIT_A1 = 22,

    SCR_TCR_EL1_BIT_T1SZ       = 16,
    SCR_TCR_EL1_BIT_T1SZ_WIDTH = 5,

    SCR_TCR_EL1_BIT_TG0_WIDTH = 2,
    SCR_TCR_EL1_BIT_TG0       = 14,

    SCR_TCR_EL1_BIT_SH0high = 13,
    SCR_TCR_EL1_BIT_SH0low  = 12,

    SCR_TCR_EL1_BIT_ORGN0high = 11,
    SCR_TCR_EL1_BIT_ORGN0low  = 10,

    SCR_TCR_EL1_BIT_IRGN0high  = 9,
    SCR_TCR_EL1_BIT_IRGN0low   = 8,
    SCR_TCR_EL1_BIT_EPD0       = 7,
    SCR_TCR_EL1_BIT_T0SZ       = 0,
    SCR_TCR_EL1_BIT_T0SZ_WIDTH = 6,
};

SCR_BIT32_RW_FUNCTIONS(TCR_EL2)
enum __AARCH64_SCR_TCR_EL2_BITS {
    SCR_TCR_BIT_TBI1      = 38,
    SCR_TCR_BIT_TBI0      = 37,
    SCR_TCR_BIT_AS        = 36,
    SCR_TCR_BIT_IPShigh   = 34,
    SCR_TCR_BIT_IPSmid    = 33,
    SCR_TCR_BIT_IPSlow    = 32,
    SCR_TCR_BIT_TG1       = 30,
    SCR_TCR_BIT_TG1_WIDTH = 2,
    SCR_TCR_BIT_TG1high   = 31,
    SCR_TCR_BIT_TG1low    = 30,
    SCR_TCR_BIT_SH1high   = 29,
    SCR_TCR_BIT_SH1low    = 28,
    SCR_TCR_BIT_ORGN1high = 27,
    SCR_TCR_BIT_ORGN1low  = 26,

    SCR_TCR_BIT_IRGN1high = 25,
    SCR_TCR_BIT_IRGN1low  = 24,

    SCR_TCR_BIT_EPD1 = 23,

    SCR_TCR_BIT_A1 = 22,

    SCR_TCR_BIT_T1SZ       = 16,
    SCR_TCR_BIT_T1SZ_WIDTH = 5,

    SCR_TCR_BIT_TBI      = 20,
    SCR_TCR_BIT_PS_WIDTH = 3,
    SCR_TCR_BIT_PS       = 16,

    SCR_TCR_BIT_TG0_WIDTH = 2,
    SCR_TCR_BIT_TG0       = 14,

    SCR_TCR_BIT_SH0high = 13,
    SCR_TCR_BIT_SH0low  = 12,

    SCR_TCR_BIT_ORGN0high = 11,
    SCR_TCR_BIT_ORGN0low  = 10,

    SCR_TCR_BIT_IRGN0high  = 9,
    SCR_TCR_BIT_IRGN0low   = 8,
    SCR_TCR_BIT_EPD0       = 7,
    SCR_TCR_BIT_T0SZ       = 0,
    SCR_TCR_BIT_T0SZ_WIDTH = 6,
};

SCR_BIT64_RW_FUNCTIONS(DACR32_EL2)
enum __AARCH64_SCR_DACR32_EL2_BITS {
    SCR_DACR_BIT_Dn_BEGIN = 0,
    SCR_DACR_BIT_Dn_WIDTH = 2,
    SCR_DACR_BIT_Dn_COUNT = 16,

    SCR_DACR_NOACCESS = 0x0,
    SCR_DACR_CLIENT   = 0x1,
    SCR_DACR_MANAGER  = 0x3,
};

SCR_BIT64_RW_FUNCTIONS(SCR_EL3)
enum __AARCH64_SCR_SCR_EL3_BITS {
    SCR_SCR_BIT_TWE = 13,
    SCR_SCR_BIT_TWI = 12,
    SCR_SCR_BIT_ST  = 11,
    SCR_SCR_BIT_RW  = 10,
    SCR_SCR_BIT_SIF = 9,
    SCR_SCR_BIT_HCE = 8,
    SCR_SCR_BIT_SMD = 7,
    SCR_SCR_BIT_EA  = 3,
    SCR_SCR_BIT_FIQ = 2,
    SCR_SCR_BIT_IRQ = 1,
    SCR_SCR_BIT_NS  = 0,
};

SCR_BIT64_RW_FUNCTIONS(PAR_EL1)
enum __AARCH64_SCR_PAR_EL1_SUCCESS_BITS {
    SCR_PAR_BIT_AttrH       = 60,
    SCR_PAR_BIT_AttrH_WIDTH = 4,

    SCR_PAR_BIT_AttrL       = 56,
    SCR_PAR_BIT_AttrL_WIDTH = 4,

    SCR_PAR_BIT_PA       = 12,
    SCR_PAR_BIT_PA_WIDTH = 36,

    SCR_PAR_BIT_NS             = 9,
    SCR_PAR_BIT_SHA_LOW        = 7,
    SCR_PAR_BIT_SHA_HIGH       = 8,
    SCR_PAR_BIT_SHA_NONSHARE   = 0,
    SCR_PAR_BIT_SHA_OUTERSHARE = 2,
    SCR_PAR_BIT_SHA_INNERSHARE = 3,

    SCR_PAR_BIT_F_SUCCESS = 0,
};
enum __AARCH64_SCR_PAR_EL1_ABORT_BITS {
    SCR_PAR_BIT_S             = 9,
    SCR_PAR_BIT_PTW           = 8,
    SCR_PAR_BIT_SHA_FST       = 1,
    SCR_PAR_BIT_SHA_FST_WIDTH = 6,

    SCR_PAR_BIT_F = 0,
};

SCR_BIT64_RW_FUNCTIONS(IFSR32_EL2)
SCR_BIT64_RW_FUNCTIONS(FAR_EL1)

SCR_BIT64_RW_FUNCTIONS(MAIR_EL1)

enum __AARCH64_SCR_MAIR_EL1_BITS {
    SCR_MAIR_BIT_Attr_BEGIN = 0,
    SCR_MAIR_BIT_Attr_WIDTH = 8,
    SCR_MAIR_BIT_Attr_COUNT = 8,
};

SCR_RW_FUNCTIONS_V(FPEXC)
SCR_RW_FUNCTIONS_V(FPSCR)
SCR_RW_FUNCTIONS_V(FPSID)

SCR_BIT64_RW_FUNCTIONS(CCSIDR_EL1)
enum __AARCH64_SCR_CCSIDR_EL1_BITS {
    SCR_CCSIDR_BIT_WT                  = 31,
    SCR_CCSIDR_BIT_WB                  = 30,
    SCR_CCSIDR_BIT_RA                  = 29,
    SCR_CCSIDR_BIT_WA                  = 28,
    SCR_CCSIDR_BIT_NumSets             = 13,
    SCR_CCSIDR_BIT_NumSets_WIDTH       = 15,
    SCR_CCSIDR_BIT_Associativity       = 3,
    SCR_CCSIDR_BIT_Associativity_WIDTH = 10,
    SCR_CCSIDR_BIT_LineSize            = 0,
    SCR_CCSIDR_BIT_LineSize_WIDTH      = 3,
};

SCR_BIT64_RW_FUNCTIONS(CLIDR_EL1)
enum __AARCH64_SCR_CLIDR_EL1_BITS {
    SCR_CLIDR_BIT_CTYPE_BEGIN = 0,
    SCR_CLIDR_BIT_CTYPE_COUNT = 3,
    SCR_CLIDR_BIT_CTYPE_WIDTH = 3,
    SCR_CLIDR_BIT_LOUIS       = 21,
    SCR_CLIDR_BIT_LOUIS_WIDTH = 3,
    SCR_CLIDR_BIT_LOC         = 24,
    SCR_CLIDR_BIT_LOC_WIDTH   = 3,
    SCR_CLIDR_BIT_LOUU        = 27,
    SCR_CLIDR_BIT_LOUU_WIDTH  = 3,
    SCR_CLIDR_BIT_ICB         = 30,
    SCR_CLIDR_BIT_ICB_WIDTH   = 3,

    SCR_CLIDR_CTYPE_NoCache  = 0,
    SCR_CLIDR_CTYPE_ICache   = 1,
    SCR_CLIDR_CTYPE_DCache   = 2,
    SCR_CLIDR_CTYPE_SIDCache = 3,
    SCR_CLIDR_CTYPE_UCache   = 4,
};

SCR_BIT64_RW_FUNCTIONS(CSSELR_EL1)
enum __AARCH64_SCR_CSSELR_EL1_BITS {
    SCR_CSSELR_BIT_LEVEL       = 1,
    SCR_CSSELR_BIT_LEVEL_WIDTH = 3,
    SCR_CSSELR_BIT_InD         = 0,
};

#define DCISW   S1_0_C7_C6_2
#define DCCISW  S1_0_C7_C14_2
#define DCCSW   S1_0_C7_C10_2
#define DCIVAC  S1_0_C7_C6_1
#define DCCVAC  S1_3_C7_C10_1
#define DCCVAP  S1_3_C7_C12_1
#define DCCVAU  S1_3_C7_C11_1
#define ICIALLU S1_0_C7_C5_0
static inline void scr_write_DCCISW(uint64_t value)
{
    asm volatile("DC CISW,%0\n\t" : "=r"(value));
}
static inline void scr_write_DCCSW(uint64_t value)
{
    asm volatile("DC CSW,%0\n\t" : "=r"(value));
}
static inline void scr_write_DCISW(uint64_t value)
{
    asm volatile("DC ISW,%0\n\t" : "=r"(value));
}
static inline void scr_write_ICIALLU(void)
{
    asm volatile("IC IALLU\n\t");
}

SCR_BIT64_RW_FUNCTIONS(PMCCNTR_EL0)
enum __AARCH64_SCR_PMCNTENSET_EL0_BITS {
    SCR_PMCNTENSET_BIT_C  = 31,
    SCR_PMCNTENSET_BIT_Px = 0,
};
SCR_BIT64_RW_FUNCTIONS(PMCR_EL0)
enum __AARCH64_SCR_PMCR_EL0_BITS {
    SCR_PMCR_BIT_IMP_BEGIN = 24,
    SCR_PMCR_BIT_IMP_WIDTH = 8,

    SCR_PMCR_BIT_IDCODE_BEGIN = 16,
    SCR_PMCR_BIT_IDCODE_WIDTH = 8,

    SCR_PMCR_BIT_N_BEGIN = 11,
    SCR_PMCR_BIT_N_WIDTH = 6,

    SCR_PMCR_BIT_LC = 6,
    SCR_PMCR_BIT_DP = 5,
    SCR_PMCR_BIT_X  = 4,
    SCR_PMCR_BIT_D  = 3,
    SCR_PMCR_BIT_C  = 2,
    SCR_PMCR_BIT_P  = 1,
    SCR_PMCR_BIT_E  = 0,
};
SCR_BIT64_RW_FUNCTIONS(PMUSERENR_EL0)
enum __AARCH64_SCR_PMUSERENR_EL0_BITS {
    SCR_PMUSERENR_BIT_ER = 3,
    SCR_PMUSERENR_BIT_CR = 2,
    SCR_PMUSERENR_BIT_SW = 1,
    SCR_PMUSERENR_BIT_EN = 0,
};

enum SCR_TLB_BITS {
    SCR_TLB_BIT_MVA       = 12,
    SCR_TLB_BIT_MVA_WIDTH = 20,
    SCR_TLB_BIT_ASID      = 48,
    SCR_TLB_BIT_WIDTH     = 16,
};

SCR_BIT64_WO_FUNCTIONS(vbar_el3)
SCR_BIT64_WO_FUNCTIONS(vbar_el2)
SCR_BIT64_WO_FUNCTIONS(vbar_el1)

SCR_BIT64_RO_FUNCTIONS(S3_1_C15_C3_0)
SCR_BIT64_RO_FUNCTIONS(s3_4_c12_c9_5)

SCR_BIT64_RO_FUNCTIONS(CNTFRQ_EL0)
SCR_BIT32_RO_FUNCTIONS(ASDSAA)
SCR_BIT32_RW_FUNCTIONS(CNTP_CTL_EL0)
SCR_BIT64_RW_FUNCTIONS(CNTP_CV_AL_EL0)
SCR_BIT32_RW_FUNCTIONS(CNTP_TVAL_EL0)

SCR_BIT32_RO_FUNCTIONS(NZCV)
SCR_BIT32_RO_FUNCTIONS(DAIF)
SCR_BIT32_RO_FUNCTIONS(CurrentEL)
SCR_BIT32_RW_FUNCTIONS(SCTLR_EL1)
SCR_BIT32_RW_FUNCTIONS(SCTLR_EL2)
SCR_BIT32_RO_FUNCTIONS(SCTLR_EL3)
SCR_BIT32_RW_FUNCTIONS(ESR_EL1)
SCR_BIT64_RW_FUNCTIONS(SPSR_EL1)

#ifdef CONFIG_ARCH_AARCH64
#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
#define ICC_DIR_EL1     S3_0_C12_C11_1
#define ICC_SRE_EL1     S3_0_C12_C12_5
#define ICC_SRE_EL2     S3_4_C12_C9_5
#define ICC_SRE_EL3     S3_6_C12_C12_5
#define ICC_CTLR_EL1    S3_0_C12_C12_4
#define ICC_CTLR_EL3    S3_6_C12_C12_4
#define ICC_PMR_EL1     S3_0_C4_C6_0
#define ICC_RPR_EL1     S3_0_C12_C11_3
#define ICC_IGRPEN1_EL3 S3_6_c12_c12_7
#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
#define ICC_IGRPEN0_EL1 S3_0_c12_c12_6
#define ICC_HPPIR0_EL1  S3_0_c12_c8_2
#define ICC_HPPIR1_EL1  S3_0_c12_c12_2
#define ICC_IAR0_EL1    S3_0_c12_c8_0
#define ICC_IAR1_EL1    S3_0_c12_c12_0
#define ICC_EOIR0_EL1   S3_0_c12_c8_1
#define ICC_EOIR1_EL1   S3_0_c12_c12_1
#define ICC_SGI0R_EL1   S3_0_c12_c11_7
#define ICC_SGI1R_EL1   S3_0_C12_C11_5
#define ICC_BPR1_EL1    S3_0_C12_C12_3
#define MPIDR           mpidr_el1

#else
#define ICC_IAR1_EL1    p15, 0, % 0, c12, c12, 0
#define ICC_EOIR1_EL1   p15, 0, % 0, c12, c12, 1
#define ICC_HPPIR1_EL1  p15, 0, % 0, c12, c12, 2
#define ICC_BPR1_EL1    p15, 0, % 0, c12, c12, 3
#define ICC_DIR_EL1     p15, 0, % 0, c12, c11, 1
#define ICC_PMR_EL1     p15, 0, % 0, c4, c6, 0
#define ICC_SGI1R_EL1   p15, 0, % Q0, % R0, c12
#define ICC_CTLR_EL1    p15, 0, % 0, c12, c12, 4
#define ICC_IGRPEN1_EL1 p15, 0, % 0, c12, c12, 7
#define ICC_SRE_EL1     p15, 0, % 0, c12, c12, 5
#define MPIDR           p15, 0, % 0, c0, c0, 5
#endif
SCR_BIT32_RW_FUNCTIONS(ICC_IAR1_EL1);
SCR_BIT64_RW_FUNCTIONS(ICC_EOIR1_EL1);
SCR_BIT64_RW_FUNCTIONS(ICC_DIR_EL1);
SCR_BIT64_RO_FUNCTIONS(ICC_HPPIR1_EL1);
SCR_BIT32_RW_FUNCTIONS(ICC_SRE_EL1);
SCR_BIT64_RW_FUNCTIONS(ICC_BPR1_EL1);
SCR_BIT32_RW_FUNCTIONS(ICC_PMR_EL1);
SCR_BIT64_RW_FUNCTIONS(ICC_CTLR_EL1);
SCR_BIT64_RW_FUNCTIONS(ICC_RPR_EL1);
SCR_BIT64_RW_FUNCTIONS(ICC_SGI1R_EL1);
SCR_BIT32_RW_FUNCTIONS(ICC_IGRPEN1_EL1);
SCR_BIT64_RW_FUNCTIONS(MPIDR);

#else

enum __AARCH32_SCR_SCTLR_BITS {
    SCR_SCTLR_BIT_TE      = 30,
    SCR_SCTLR_BIT_AFE     = 29,
    SCR_SCTLR_BIT_TRE     = 28,
    SCR_SCTLR_BIT_NMFI_RO = 27,
    SCR_SCTLR_BIT_EE      = 25,
    SCR_SCTLR_BIT_UWXN    = 20,
    SCR_SCTLR_BIT_WXN     = 19,
    SCR_SCTLR_BIT_nTWE    = 18,
    SCR_SCTLR_BIT_nTWI    = 16,
    SCR_SCTLR_BIT_V       = 13,
    SCR_SCTLR_BIT_I       = 12,
    SCR_SCTLR_BIT_SED     = 8,
    SCR_SCTLR_BIT_ITD     = 7,
    SCR_SCTLR_BIT_THEE    = 6,
    SCR_SCTLR_BIT_CP15BEN = 5,
    SCR_SCTLR_BIT_C       = 2,
    SCR_SCTLR_BIT_A       = 1,
    SCR_SCTLR_BIT_M       = 0,
};

enum __AARCH32_SCR_SCR_BITS {
    SCR_SCR_BIT_TWE = 13,
    SCR_SCR_BIT_TWI = 12,
    SCR_SCR_BIT_SIF = 9,
    SCR_SCR_BIT_HCE = 8,
    SCR_SCR_BIT_SCD = 7,
    SCR_SCR_BIT_nET = 6,
    SCR_SCR_BIT_AW  = 5,
    SCR_SCR_BIT_FW  = 4,
    SCR_SCR_BIT_EA  = 3,
    SCR_SCR_BIT_FIQ = 2,
    SCR_SCR_BIT_IRQ = 1,
    SCR_SCR_BIT_NS  = 0,
};

enum __AARCH32_SCR_TTBCR_SHORT_DESCRIPTOR_BITS {
    SCR_TTBCR_BIT_EAE = 31,

    SCR_TTBCR_BIT_PD1 = 5,
    SCR_TTBCR_BIT_PD0 = 4,

    SCR_TTBCR_BIT_N       = 0,
    SCR_TTBCR_BIT_N_WIDTH = 3,
};
enum __AARCH32_SCR_TTBCR_LONG_DESCRIPTOR_BITS {
    SCR_TTBCR_BIT_EAE = 31,

    SCR_TTBCR_BIT_SH1high = 29,
    SCR_TTBCR_BIT_SH1low  = 28,

    SCR_TTBCR_BIT_ORGN1high = 27,
    SCR_TTBCR_BIT_ORGN1low  = 26,

    SCR_TTBCR_BIT_IRGN1high = 25,
    SCR_TTBCR_BIT_IRGN1low  = 24,

    SCR_TTBCR_BIT_EPD1 = 23,

    SCR_TTBCR_BIT_A1 = 22,

    SCR_TTBCR_BIT_T1SZhigh = 18,
    SCR_TTBCR_BIT_T1SZmid  = 17,
    SCR_TTBCR_BIT_T1SZlow  = 16,

    SCR_TTBCR_BIT_SH0high = 13,
    SCR_TTBCR_BIT_SH0low  = 12,

    SCR_TTBCR_BIT_ORGN0high = 11,
    SCR_TTBCR_BIT_ORGN0low  = 10,

    SCR_TTBCR_BIT_IRGN0high = 9,
    SCR_TTBCR_BIT_IRGN0low  = 8,

    SCR_TTBCR_BIT_EPD0 = 7,

    SCR_TTBCR_BIT_T0SZhigh = 2,
    SCR_TTBCR_BIT_T0SZmid  = 1,
    SCR_TTBCR_BIT_T0SZlow  = 0,
};

enum __AARCH32_SCR_TTBRx_BITS {
    SCR_TTBRx_BIT_BASEADDR       = 0,
    SCR_TTBRx_BIT_BASEADDR_WIDTH = 48,

    SCR_TTBRx_BIT_ASID       = 48,
    SCR_TTBRx_BIT_ASID_WIDTH = 8,

};
enum __AARCH32_SCR_DACR_BITS {
    SCR_DACR_BIT_Dn_BEGIN = 0,
    SCR_DACR_BIT_Dn_WIDTH = 2,
    SCR_DACR_BIT_Dn_COUNT = 16,

    SCR_DACR_NOACCESS = 0x0,
    SCR_DACR_CLIENT   = 0x1,
    SCR_DACR_MANAGER  = 0x3,
};

SCR_RW_FUNCTIONS32(DFSR, p15, 0, c5, c0, 0)
SCR_RW_FUNCTIONS32(IFSR, p15, 0, c5, c0, 1)
SCR_RO_FUNCTIONS32(ADFSR, p15, 0, c5, c1, 0)
SCR_RO_FUNCTIONS32(AIFSR, p15, 0, c5, c1, 1)
SCR_RW_FUNCTIONS32(DFAR, p15, 0, c6, c0, 0)
SCR_RW_FUNCTIONS32(IFAR, p15, 0, c6, c0, 2)
SCR_WO_FUNCTIONS32(ATS1CPR, p15, 0, c7, c8, 0)
SCR_WO_FUNCTIONS32(ATS1CPW, p15, 0, c7, c8, 1)
SCR_WO_FUNCTIONS32(ATS1CUR, p15, 0, c7, c8, 2)
SCR_WO_FUNCTIONS32(ATS1CUW, p15, 0, c7, c8, 3)

enum __AARCH32_SCR_PRRR_BITS {
    SCR_PRRR_BIT_TR_BEGIN = 0,
    SCR_PRRR_BIT_TR_WIDTH = 2,
    SCR_PRRR_BIT_TR_COUNT = 8,

    SCR_PRRR_TR_Dn  = 0x0,
    SCR_PRRR_TR_Dnn = 0x1,
    SCR_PRRR_TR_NM  = 0x2,

    SCR_PRRR_BIT_DS0 = 16,
    SCR_PRRR_BIT_DS1 = 17,
    SCR_PRRR_BIT_NS0 = 18,
    SCR_PRRR_BIT_NS1 = 19,

    SCR_PRRR_BIT_NOR_BEGIN = 24,
    SCR_PRRR_BIT_NOR_WIDTH = 1,
    SCR_PRRR_BIT_NOR_COUNT = 8,
};

enum __AARCH32_SCR_NMRR_BITS {
    SCR_NMRR_BIT_OR_BEGIN = 16,
    SCR_NMRR_BIT_OR_WIDTH = 2,
    SCR_NMRR_BIT_OR_COUNT = 8,

    SCR_NMRR_BIT_IR_BEGIN = 16,
    SCR_NMRR_BIT_IR_WIDTH = 2,
    SCR_NMRR_BIT_IR_COUNT = 8,

    SCR_NMRR_NC    = 0,
    SCR_NMRR_WBWA  = 0x1,
    SCR_NMRR_WTNWA = 0x2,
    SCR_NMRR_WBNWA = 0x3,
};

SCR_RW_FUNCTIONS32(TPIDRPRW, p15, 0, c13, c0, 4)
SCR_RW_FUNCTIONS32(TPIDRURO, p15, 0, c13, c0, 3)
SCR_RW_FUNCTIONS32(TPIDRURW, p15, 0, c13, c0, 2)
SCR_RW_FUNCTIONS32(CONTEXTIDR, p15, 0, c13, c0, 1)

enum __AARCH32_SCR_CCSIDR_BITS {
    SCR_CCSIDR_BIT_WT                  = 31,
    SCR_CCSIDR_BIT_WB                  = 30,
    SCR_CCSIDR_BIT_RA                  = 29,
    SCR_CCSIDR_BIT_WA                  = 28,
    SCR_CCSIDR_BIT_NumSets             = 13,
    SCR_CCSIDR_BIT_NumSets_WIDTH       = 15,
    SCR_CCSIDR_BIT_Associativity       = 3,
    SCR_CCSIDR_BIT_Associativity_WIDTH = 10,
    SCR_CCSIDR_BIT_LineSize            = 0,
    SCR_CCSIDR_BIT_LineSize_WIDTH      = 3,
};

enum __AARCH32_SCR_CLIDR_BITS {
    SCR_CLIDR_BIT_CTYPE_BEGIN = 0,
    SCR_CLIDR_BIT_CTYPE_COUNT = 3,
    SCR_CLIDR_BIT_CTYPE_WIDTH = 3,
    SCR_CLIDR_BIT_LOUIS       = 21,
    SCR_CLIDR_BIT_LOUIS_WIDTH = 3,
    SCR_CLIDR_BIT_LOC         = 24,
    SCR_CLIDR_BIT_LOC_WIDTH   = 3,
    SCR_CLIDR_BIT_LOUU        = 27,
    SCR_CLIDR_BIT_LOUU_WIDTH  = 3,
};

enum __AARCH32_SCR_CSSELR_BITS {
    SCR_CSSELR_BIT_LEVEL       = 1,
    SCR_CSSELR_BIT_LEVEL_WIDTH = 3,
    SCR_CSSELR_BIT_InD         = 0,
};

SCR_WO_FUNCTIONS32(BPIALL, p15, 0, c7, c5, 6)
SCR_WO_FUNCTIONS32(BPIALLIS, p15, 0, c7, c1, 6)
SCR_WO_FUNCTIONS32(BPIMVA, p15, 0, c7, c5, 7)
SCR_WO_FUNCTIONS32(DCCIMVAC, p15, 0, c7, c14, 1)
SCR_WO_FUNCTIONS32(DCCISW, p15, 0, c7, c14, 2)
SCR_WO_FUNCTIONS32(DCCMVAC, p15, 0, c7, c10, 1)
SCR_WO_FUNCTIONS32(DCCMVAU, p15, 0, c7, c11, 1)
SCR_WO_FUNCTIONS32(DCCSW, p15, 0, c7, c10, 2)
SCR_WO_FUNCTIONS32(DCIMVAC, p15, 0, c7, c6, 1)
SCR_WO_FUNCTIONS32(DCISW, p15, 0, c7, c6, 2)
SCR_WO_FUNCTIONS32(ICIALLU, p15, 0, c7, c5, 0)
SCR_WO_FUNCTIONS32(ICIALLUIS, p15, 0, c7, c1, 0)
SCR_WO_FUNCTIONS32(ICIMVAU, p15, 0, c7, c5, 1)

SCR_WO_FUNCTIONS32(DTLBIALL, p15, 0, c8, c6, 0)
SCR_WO_FUNCTIONS32(DTLBIASID, p15, 0, c8, c6, 2)
SCR_WO_FUNCTIONS32(DTLBIMVA, p15, 0, c8, c6, 1)
SCR_WO_FUNCTIONS32(ITLBIALL, p15, 0, c8, c5, 0)
SCR_WO_FUNCTIONS32(ITLBIASID, p15, 0, c8, c5, 2)
SCR_WO_FUNCTIONS32(ITLBIMVA, p15, 0, c8, c5, 1)
SCR_WO_FUNCTIONS32(TLBIALL, p15, 0, c8, c7, 0)
SCR_WO_FUNCTIONS32(TLBIALLIS, p15, 0, c8, c3, 0)
SCR_WO_FUNCTIONS32(TLBIASID, p15, 0, c8, c7, 2)
SCR_WO_FUNCTIONS32(TLBIASIDIS, p15, 0, c8, c3, 2)
SCR_WO_FUNCTIONS32(TLBIMVAA, p15, 0, c8, c7, 3)
SCR_WO_FUNCTIONS32(TLBIMVAAIS, p15, 0, c8, c3, 3)
SCR_WO_FUNCTIONS32(TLBIMVA, p15, 0, c8, c7, 1)
SCR_WO_FUNCTIONS32(TLBIMVAIS, p15, 0, c8, c3, 1)

SCR_RW_FUNCTIONS(PMCR, p15, 0, c9, c12, 0)
SCR_RW_FUNCTIONS(PMCNTENSET, p15, 0, c9, c12, 1)
SCR_RW_FUNCTIONS(PMCNTENCLR, p15, 0, c9, c12, 2)
SCR_RW_FUNCTIONS(PMOVSR, p15, 0, c9, c12, 3)
SCR_WO_FUNCTIONS(PMSWINC, p15, 0, c9, c12, 4)
SCR_RW_FUNCTIONS(PMSELR, p15, 0, c9, c12, 5)
SCR_RO_FUNCTIONS(PMCEID0, p15, 0, c9, c12, 6)
SCR_RO_FUNCTIONS(PMCEID1, p15, 0, c9, c12, 7)

SCR_RW_FUNCTIONS(PMXEVTYPER, p15, 0, c9, c13, 1)
SCR_RW_FUNCTIONS(PMXEVCNTR, p15, 0, c9, c13, 2)
SCR_RW_FUNCTIONS(PMUSERENR, p15, 0, c9, c14, 0)
SCR_RW_FUNCTIONS(PMINTENSET, p15, 0, c9, c14, 1)
SCR_RW_FUNCTIONS(PMINTENCLR, p15, 0, c9, c14, 2)
SCR_RW_FUNCTIONS(PMOVSSET, p15, 0, c9, c14, 3)

enum __SCR_PMCR_BITS {
    SCR_PMCR_BIT_DP = 5,
    SCR_PMCR_BIT_X  = 4,
    SCR_PMCR_BIT_D  = 3,
    SCR_PMCR_BIT_C  = 2,
    SCR_PMCR_BIT_P  = 1,
    SCR_PMCR_BIT_E  = 0,
};

enum __SCR_PMUSERENR_BITS {
    SCR_PMUSERENR_BIT_EN = 0,
};
#endif
int          scr_get_cache_info(unsigned int level, unsigned int InD, int *sets, int *ways, int *linesize);
unsigned int scr_get_cache_type(unsigned int level);

void               scr_clean_data_cache(void);
void               scr_clean_invalidate_data_cache(void);
void               scr_invalidate_data_cache(void);
void               scr_enable_cpu_cache(void);
void               scr_invalidate_instruction_cache(void);
void               scr_clean_invalidate_data_cache_va(long VA);
void               flush_dcache_range(unsigned long start, unsigned long end);
static inline void cache_off(void)
{
    unsigned long sctlr_el1  = 0;
    unsigned long temp_value = 0;
    asm volatile("mrs %[sctlr_el1],sctlr_el1\n\t"
                 "ldr %[temp_value],=~(1 << 2 | 1 << 11)\n\t"
                 "and %[sctlr_el1],%[sctlr_el1],%[temp_value]\n\t"
                 "msr sctlr_el1,%[sctlr_el1]\n\t" ::[sctlr_el1] "r"(sctlr_el1),
                 [temp_value] "r"(temp_value));
}
static inline void scr_invalidate_tlb_all_el1(void)
{
    asm volatile("tlbi	vmalle1\n"
                 "dsb	sy\n"
                 "isb\n\t" ::
                     : "memory");
}

static inline void scr_invalidate_tlb_all_el2(void)
{
    asm volatile("tlbi alle2\n\t"
                 "dsb sy\n\t" ::
                     : "memory");
}

static inline void scr_invalidate_tlb_all_el3(void)
{
    asm volatile("tlbi alle3\n\t"
                 "dsb sy\n\t" ::
                     : "memory");
}

static inline void scr_invalidate_tlb_asid_el1(unsigned long asid)
{
    unsigned long value = asid;
    value <<= SCR_TLB_BIT_ASID;
    asm volatile("tlbi aside1,%0\n\t"
                 "dsb sy\n\t" ::"r"(value)
                 : "memory");
}

static inline void scr_invalidate_all_pe_tlb_asid_el1(unsigned long asid)
{
    unsigned long value = asid;
    value <<= SCR_TLB_BIT_ASID;
    asm volatile("tlbi aside1is,%0\n\t"
                 "dsb sy\n\t" ::"r"(value)
                 : "memory");
}

static inline void scr_invalidate_tlb_ipa_el1(unsigned long ipa)
{
    unsigned long value = ipa << SCR_TLB_BIT_MVA;
    asm volatile("tlbi ipas2e1,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_tlb_last_level_ipa_el1(unsigned long ipa)
{
    unsigned long value = ipa << SCR_TLB_BIT_MVA;
    asm volatile("tlbi ipas2le1,%0\n\t"
                 "dsb sy\n\t"
                 :
                 : "r"(value)
                 : "memory");
}

static inline void scr_invalidate_tlb_va_el1(unsigned long mva)
{
    unsigned long value = mva << SCR_TLB_BIT_MVA;
    asm volatile("tlbi vaae1,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_all_pe_tlb_va_el1(unsigned long mva)
{
    unsigned long value = mva << SCR_TLB_BIT_MVA;
    asm volatile("tlbi vaae1is,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_tlb_last_level_va_el1(unsigned long mva)
{
    unsigned long value = mva << SCR_TLB_BIT_MVA;
    asm volatile("tlbi vaale1,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_tlb_vaasid_el1(unsigned long mva, unsigned long asid)
{
    unsigned long value = (asid << SCR_TLB_BIT_ASID) | (mva << SCR_TLB_BIT_MVA);
    asm volatile("tlbi vae1,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_tlb_va_el2(unsigned long mva)
{
    unsigned long value = mva << SCR_TLB_BIT_MVA;
    asm volatile("tlbi vae2,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_tlb_va_el3(unsigned long mva)
{
    unsigned long value = mva << SCR_TLB_BIT_MVA;
    asm volatile("tlbi vae3,%0\n\t"
                 "dsb sy\n\t"
                 : "=r"(value)::"memory");
}

static inline void scr_invalidate_tlb_vmall_el1(void)
{
    asm volatile("tlbi vmalle1\n\t" ::: "memory");
}

void scr_dump_info(void);

#endif
